Skip to content

WeBWorK 2.21 Release Candidate#2940

Open
drgrice1 wants to merge 456 commits into
mainfrom
WeBWorK-2.21
Open

WeBWorK 2.21 Release Candidate#2940
drgrice1 wants to merge 456 commits into
mainfrom
WeBWorK-2.21

Conversation

@drgrice1

Copy link
Copy Markdown
Member

This is the release candidate for WeBWorK 2.21. Please re-target any pull requests that you want to get into the release for this branch.

drgrice1 and others added 30 commits February 1, 2026 14:50
between selecting single or multiple sets in the import sets form.
This uses translations for the text from data attributes.

The `(taken from filenames)` text that is put into the value for the
"Import sets with names" input is also translated using a data
attribute.
Fix problem_data with problem randomization and show me another.
Fix sets manager import form selection multiple default option selected issue.
The instructor links help is updated to order the links in the help in
the same order that they are in the site navigation.  Also add help for
the "Job Manager" which was missing.

Also fix the links the PG problem editor help.  The links above the
CodeMirror editor window in the PG problem editor have changed in two
ways that the links in the help were not updated to match.

First, the "Problem Techniques" button was replaced with the "Sample
Problems" button.  So that Wiki link is now also removed from the help,
and it is now the local server sample problems link.

The PGML lab was updated so that it does not need the PGML-lab.pg file
in the templates directory of the course.  It now directly uses that
problem from the assets/pg directory.  The link in the help file now
does the same thing.

I removed the `reference-link` class from the links above the CodeMirror
window because that class does not do anything.  I also removed the
old webwork.maa.org links in the comments because those don't need to be
there even if they are updated to the new locations.
Rework the single problem grader interface.
This is achieved by displaying the student nav on the problem set page
for users that have the permission to act as a user as well as always
showing the student nav in problems and in tests.

If you are acting as a user, then the student nav looks the same as
before with the next and previous buttons and the name of the user that
is currently being acted as shown on the button.  However, if you are
not currently acting as another user, then the next and previous buttons
are not shown and the button says "Select Student to Act As" (or in a
test it says "Select a Test to Review").

Also fix the breadcrumb in a test when the set is not valid, but the
setID does have the `setID,v?` format.  Currently if you are acting as a
student user and reviewing a test version, say "test,v1", but you have
not worked the test, and you click the "Stop Acting" button, then the
message stating that the selected test is not valid for the user is
shown (it would be nice to not show this even) and the breadcrumb ends
with the inactive link "test,v1", and you can only go back to the
assignments page. Now, the "setID" link is shown and works, and the
inactive "v1" link is at the end.

This is built on top of #2875 since it would conflict rather heavily
with that pull request if it were not.
Make it much easier to act as a student.
Add an "accommodation time factor" to provide for extra time on timed tests.
In most cases the `webwork.maa.org` links have been updated to their new
locations.  However, there are some exceptions and other things noted
below.

In addition to updating links in the `README.md` file, the file was
generally cleaned up and issues reported by markdown lint fixed.

For example, a markdown file must have a single top level header and it
must be the first line of the file.  So the `Welcome to WeBWorK` header
was moved before the license.  I would actually like to remove the
license from the file as well.  It is not standard practice to include
that here.  It is in the `LICENSE` file.  That should be enough. Perhaps
a link to the license could be here instead?

Also, the bare links were replaced with markdown links with link text
instead of directly showing the URL.

The `webwork.maa.org` links in the files in the
`courses.dist/modelCourse/templates/setDemo` directory were not updated.
I have another plan for the `Demo` set that will be in a future pull
request.

The `$webworkURLs{docs}` configuration variable (in `defaults.config`)
was not updated, but was deleted. The only place that was used was to
pass that to PG in `lib/WeBWorK/Utils/Rendering.pm`.  However, PG
doesn't use that.  So that usage was removed as well.
The CAPA problems have now been removed from the Contrib section of the
OPL (see openwebwork/webwork-open-problem-library#1277).
So this is not needed anymore.

Note that the `courses.dist/modelCourse/templates/setDemo/prob0837.pg`
problem is already unused (it is not in the `setDemo.def` file).
The color scheme (dark or light) that is used is automatically detected
from the browser's settings initially, but can be set via a color scheme
chooser in the page header.

PG problems are still rendered in light mode regardless of the color
mode for the rest of the page.  Converting PG to honor dark mode will
take some work. Note that there are some small changes needed for the
image view dialog and knowls of PG to make sure that those dialogs
render in light mode. There is also a minor change to make the scaffold
buttons stay in light mode as well.

Note that there were some issues with light mode (i.e., the existing
themes).  The contrast of the links in the site nav were not good when
they were focused or hovered over with the mouse. This was due to an
override of the link focus styles that made the colors lighter in those
cases. That was needed for links in the masthead (the page header), but
generally was bad elsewhere. So instead this uses the Bootstrap defaults
for the hover/active colors which darkens the colors instead of
lightening them.  So now there is just a special case for links in the
masthead, and the other links use bootstraps default colors which gives
higher contrast in the site nav.

One side advantage of the above approach since it darkens links on hover
and focus instead of lightening them is that I can finally switch to a
link color for the math4-yellow theme that is not off theme.  Previously
it was a reddish color that I never really like in the scope of the
theme, but was needed for contrast.  Now it uses a rather dark yellow
and gives a more consistent feel for the theme.

The MathJax `no-dark-mode` extension has been converted into a
`bs-color-scheme` extension which rewrites the MathJax styles to honor
the `data-bs-theme` value instead of using media queries for the browser
mode.  This means that MathJax will display in the correct mode wherever
the element is in the page.  For example, on a problem page the math in
the problem will always be in light mode.  On the problem grader page
the math in the problem there will also be in light mode, but the
formula student answers will be in dark mode if the page is set to that.
Note that the MathJax dialogs will always be in dark mode if the page is
set to that since those are injected outside of the problem content div.
The menu will also always be dark mode in a problem if the page is set
to that since there isn't an override for the menu in the
`data-bs-theme` extension.  Its styles work differently.

Note that there was a small change needed for the PG CodeMirror editor
to give its default light theme a white background.  This was done in
the `pg-codemirror-editor` repository, and the new npm package published
and included in this pull request.

I am sure that I missed some colors that need to be adjusted in dark
mode and perhaps issues with forcing PG into light mode, but I can't
find anything right now.  So please check this carefully.

The `README` files in the theme directories have been deleted, and
replaced with a single `README.md` file in the parent `htdocs/themes`
directory.  It has instructions on how to create a custom theme, and
documents the Sass and CSS variables that can be set. There is a small
change in `ConfigValues.pm` to only list directories when listing theme
directories, and to skip this `README.md` file.
Rework the ProblemSet page so users can always see the set header
and additional set information for any set assigned to them.
Instead of giving an error message when a user tries to access
a set that is not open, lti restricted, conditional release,
or ip restricted, checkSet will set a flag which is used to
determine what information a user can see.

If a set not visible and a user cannot see hidden sets, only a
warning message is shown. In all other cases the set header
and any date information, such as when the set opens, closes,
etc, is shown. If the set is restricted due to a conditional
release, ip restrictions, or lti restrictions, a warning message
is shown informing the user of the restriction.

When a set is restricted, never show the set problems and always
show any previous taken set versions. This way users can still
access set versions they have taken for a restricted set from
a non restricted location.

Note, this is consistent with the permission `view_unoppend_sets`
description, which states it only configures if a set problems
can be seen. So this permission is no longer used to see if a
user can see set information such as open date and set header.

This also makes it so the right info panel div on the ProblemSet
page is only shown if the set header exists, and is not empty.

Translations were added to messages about IP restrictions.
…_factor is not set.

The `gen_new` method is not sufficient to create the new method for
database tables with default values for columns.  So the `newUser`
method needs to be created manually and make sure the default is set.

This was reported in issue #2910, and fixes that issue and most likely
other places where users are added or updated without explicitly setting
the `accomodation_time_factor`.
Basically, anytime that reduced scoring is not enabled or if it is but
it is before the reduced scoring period, then the sub_status needs to
also be set to the same thing as the status.  Otherwise the "unreduced"
score will not be computed correctly.  So the problem graders now take
this into account.

This fixes issue #2873.
First, if an answer is a checkbox answer with multiple parts checked,
then the `⍮` character is not handled.  This needs the same
processing as is done on the past answers page for this.

Second, the essay answers can not be put into a `Mojo::Collection` and
joined with `<br>` tags.  The result of that is a `Mojo::ByteStream`
which means that it is not escaped.  That was the original point since
the `<br>` tags cannot be escaped.  However, the answers must be escaped
so that answers like `<script>alert('xss attack')</script>` are not
executed.  So a for loop similar to that used for the checkbox answers
must be used.  Note that these answers were also wrapped in a redundant
`<div>` tag with the same class as the containing `<div>` that is still
there, and that was removed.

Third, there was a dangling end `</div>` tag for formula answers that
was removed.
This implements the specification detailed at
https://www.imsglobal.org/spec/lti-dr/v1p0.

To use this the LMS administrator enters the URL
`https://your.webwork2.server.edu/webwork2/ltiadvantage/registration`.
That automatically adds the LTI 1.3 configuration for the webwork2
server to the LMS.  Then the LMS administrator just needs to activate
the tool.

On the webwork2 side of things the LTI 1.3 configuration for the LMS
will be saved into a file in the directory `webwork/DATA/LTIRegistrationRequests`.
The file will be named `$lmsName-XXXX.conf` where `$lmsName` is whatever
the tool reported in the `product_family_code` subkey of the
`https://purl.imsglobal.org/spec/lti-platform-configuration` key in the
configuration webwork2 obtains from the LMS and `XXXX` is whatever
`tempfile` fills in to ensure the file is unique.  Note that the
`product_family_code` is "moodle", "canvas", etc. Unfortunately, there
isn't really a unique identifier that can be used here in the
information sent from the LMS, so not much better can be done for the
file name.

The webwork2 system administrator then needs to copy and paste the
contents of that file into either the `conf/authen_LTI_1_3.conf` file
for site wide setup, or into all of the appropriate `course.conf` files
for course specific setup. Note that depending on the LMS the data in
the file may not be complete. The specification essentially states that
it is optional for the LMS to sent this value.  Moodle sends the
`deployment_id` in the returned configuration, but Canvas does not.  Of
course I don't know what D2L or Blackboard will do.  In this case the
generated will contain `'obtain from LMS administrator`' for the
`$LTI{v1p3}{DeploymentID}`.  So for Canvas, at least, the webwork2
administrator will still need to communicate with the LMS administrator
to obtain the `deployment_id`.  Eventually, a user interface in the
admin course could perhaps be implemented for dealing with these
configurations in a nicer way than cutting a pasting from this file that
is created.  However, that most likely will require a change in how the
LTI configurations are saved. The config file approach is a limiting
factor in this.

Also, there may be additional configuration that the LMS administrator
needs (or may want) to do, and how the tool is presented in the LMS when
editing it may be different than how it was previously with the manual
configuration approach.

For Moodle the tool that is automatically created needs to be activated
(a click of a button does this), but furthermore, the administrator will
probably want to edit the configuration and set the "Tool configuration
usage" to "Show in activity chooser and as preconfigured tool" (it is
set to "Show as preconfigured tool when adding an external tool" by
default), and set "Default launch container" to "New Window" (it is set
to "Embed, without blocks" by default). Also, the way the tool is
presented when editing it is indistinguishable from a tool created using
the manual configuration approach.  This means that all aspects of the
tool can be edited as before.

For Canvas even before the tool is created in the LMS there are some
options that can be configured although usually they should be left with
the defaults.  The only things that can be changed are if certain things
in the configuration from webwork2 are enabled or not.  For example,
placements in the configuration from webwork2 can not be added, but can
only be disabled.  Also, the way the tool is presented when editing it
is quite different from a manually configured tool. None of the URLs can
be edited, and the things that were in the configuration from webwork
can only be disabled again.

Of course, it remains to be seen what D2L or Blackboard do with this.

Note that there is a little more that can be added to this.  Before the
tool is added to the LMS, webwork2 could present a page that allows the
LMS administrator to select options for the tool.  For example, the
current tool name will be "WeBWorK at your.webwork2.server.edu", but
that could be allowed to be changed by the LMS administrator.  Note that
for Moodle that can be changed later anyway, but Canvas does not provide
a way to change the tool name.  Also, it may be desirable to allow the
administrator to determine if grade passback is allowed or not.
Although, for both Moodle and Canvas this can still be done in any case.

Note that LTI 1.1 does support something like this, but I haven't found
any documentation on it (although I haven't looked to hard).
drdrew42 and others added 30 commits July 3, 2026 15:29
Newer Archive::Tar refuses, under its secure extract mode, to extract
symbolic and hard links whose targets fall outside the extraction
directory (the CVE-2026-42496 / CVE-2026-42497 hardening in Archive::Tar
3.08, backported into distribution perl packages), and aborts the whole
extraction when an archive contains one.

Every course archive contains the standard template links (Library,
Contrib, capaLibrary, Student_Orientation), whose relative targets point
outside the course directory, so no course could be unarchived once the
system's Archive::Tar carried the fix.

Remove the link entries and extract the remaining files with secure
extract mode still enabled -- so regular files cannot escape the course
directory via absolute or ../ paths -- then recreate the symbolic links
directly. Access through a recreated link remains governed by the
valid_symlinks course environment option, so this grants no new read
access.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When extraction fails partway through, it leaves the partially extracted
course directory behind. unarchiveCourse only moved a displaced course
back into place, so the incomplete directory remained.

For a fresh restore this left an orphaned, database-less course stub that
blocked a same-name retry with a misleading "Cannot overwrite existing
course" error. When unarchiving over an existing course it was worse:
_unarchiveCourse_move_away has already renamed the existing course to
<id>_tmp, and _unarchiveCourse_move_back then fails because renameCourse
refuses to move it back onto the name still occupied by the partial
extraction, leaving the original course stranded under _tmp.

Remove the partially extracted directory in the failure branch before
moving any displaced course back. _unarchiveCourse_move_away has already
moved a pre-existing course of this name aside, so the directory can only
be the incomplete extraction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The File Manager's tar extraction hits the same problem as course
unarchiving: newer Archive::Tar refuses, under secure extract mode, to
extract symbolic links whose targets leave the extraction directory (the
CVE-2026-42496 hardening), so an instructor extracting a tarball that
contains such links would have those links skipped with an error.

The extraction already validates each member's location with
path_is_subdir, so recreate symbolic-link members directly with symlink()
instead of extracting them. Access through the link remains governed by
the valid_symlinks course environment option.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This reworks what was done in #3008 and #3016. Rather than trying to
force the PG critic and hardcopy xml into light mode, remove the
`bg-white` class from the render panel and use the page colors. This
means that these things are in a proper dark mode for those that use it.

Problems do not need the white background since by default iframes are
given a white background.  Also the iframe elements do not need to have
the `color-scheme` style set to `light`.  That has no effect inside the
iframe anyway.
This has been deprecated since the release of webwork 2.18. It is time
for it to go.  I believe that everyone that used to use this endpoint
have now updated to use the `render_rpc` endpoint. If not, then we can
wait another release for this.
A better approach for dark mode for some rendering in the editor.
Any time that a package has certain scripts defined (such as `install`
or `postinstall`), npm now warns about them and tells you to "Run `npm
approve-scripts --allow-scripts-pending` to review, or `npm
approve-scripts <pkg>` to allow."  Note that doing so just adds the
section to the `package.json` file that you see in this pull request.

The package `@parcel/watcher` has an `install` script that rebuilds its
distribution code if an environment variable is set. This script is
harmless, but does not need to be run.

The package `iframe-resizer` has a `postinstall` script that gives a
message about the newer versions of the iframe resizer begin split into
parts. This script also does not need to be run.
… grades page.

If the "Additional Grade Information" is shown then the lack of a margin
is not good.  If that is not shown the margin doesn't do anything
particularly harmful to the layout.
Deny scripts for two npm packages.
This version fixes the issue with certain expressions causing the
browser to run out of memory and crash. See
mathjax/MathJax#3578,
https://forums.openwebwork.org/mod/forum/discuss.php?d=8819, and
openwebwork/pg#1451.

Also remove the workaround for the `--mjx-bg-alpha` variable. That is
not needed anymore.
Add a margin to the bottom of the "Future Assignments" on the student grades page.
…al-symlinks

Bugfix/unarchive course external symlinks
typos identified by github.com/crate-ci/typos
icon alert if a date has been overrided for a user on the Assignments…
configure mathjax to line break long display math
dump_tables() and NewSQL::Std::dump_table() unconditionally returned 1, so
archiveCourse()'s `unless ($dump_db_result) { croak }` guard never fired. A
mysqldump failure (wrong mysqldump path, auth failure, disk full, a MariaDB
column-statistics incompatibility, ...) therefore produced a "successful"
archive whose database was empty or missing -- discovered only later, when the
archive was unarchived and no tables were restored.

Make the failure propagate:

- dump_table() returns 0 when mysqldump exits non-zero.
- dump_tables() aggregates the per-table results and returns false if any
  table's dump failed, so archiveCourse() aborts instead of writing a DB-less
  archive.

Preserve the existing tolerance for courses created with an earlier version of
WeBWorK that predate some tables: dump_tables() skips tables that do not exist
(via tableExists) rather than treating them as failures, so only a genuine
mysqldump error aborts the archive. Because absent tables now produce no dump
file, restore_tables() skips missing dump files instead of restoring from a
nonexistent path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
typos identified by github.com/crate-ci/typos
…manager.

This just adds the `courseLinks` in the course environment to the list
of directories (and now links) that are checked when an instructor
attempts to delete a directory in the file manager.

This is to address issue #2568.
Caliper::Entity::problem_user() called $problem_user->prHintsAfter() to
populate the 'showHintsAfter' event field, but the UserProblem record has
no prHintsAfter accessor -- the field is showHintsAfter (used correctly
for the global problem in problem()). Generating a Caliper event for a
problem attempt would die with "Can't locate object method prHintsAfter".
Call showHintsAfter() instead.
typos identified by github.com/crate-ci/typos
Fix Caliper::Entity calling nonexistent prHintsAfter() method
…t-silent

Abort a course archive when the database dump actually fails
Protect the required course symbolic links from deletion in the file manager.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants